AWS IoTポリシーを変更したらpublishできなくなったので調査、修正してみた
こんにちはCX事業本部のさかじです。
サンプルでよく見るAWS IoTのポリシーを変更したところ正常にデータをpublishできなくなったので何が悪かったかを調査修正しました。
環境
- MacBook Pro(macOS Mojave 10.14.6)
前提条件
$ python3 --version Python 3.7.6
testThing
という名称でモノ作成、同様に証明書もダウンロード済み
ソース
以下のように、カウントアップデータをpublish
import os import os.path import time import json class IotMqttClient: # AWS IOTと接続するときの設定 ############### ### 要確認 ### ############### ROOT_CA_PATH = os.path.join(os.path.dirname(__file__), 'certs/rootCA.pem') CERTIFICAT_PATH = os.path.join(os.path.dirname(__file__), 'certs/cert.pem') PRIVATE_KEY_PATH = os.path.join(os.path.dirname(__file__), 'certs/private.key') IOT_HOST = 'a1caabg5j4yl8w.iot.ap-northeast-1.amazonaws.com' IOT_PORT = 8883 IOT_CLIENT_ID = 'test_client' __my_iot_mqtt_client = None __is_connected = False def __init__(self): from AWSIoTPythonSDK.MQTTLib import AWSIoTMQTTClient # クライアントの設定 self.__my_iot_mqtt_client = AWSIoTMQTTClient(self.IOT_CLIENT_ID) self.__my_iot_mqtt_client.configureEndpoint(self.IOT_HOST, self.IOT_PORT) self.__my_iot_mqtt_client.configureCredentials(self.ROOT_CA_PATH, self.PRIVATE_KEY_PATH, self.CERTIFICAT_PATH) # 接続情報の設定 self.__my_iot_mqtt_client.configureAutoReconnectBackoffTime(1, 32, 20) self.__my_iot_mqtt_client.configureOfflinePublishQueueing(-1) # Infinite offline Publish queueing self.__my_iot_mqtt_client.configureDrainingFrequency(2) # Draining: 2 Hz self.__my_iot_mqtt_client.configureConnectDisconnectTimeout(10) # 10 sec self.__my_iot_mqtt_client.configureMQTTOperationTimeout(5) # 5 sec def on_offline(): self.__is_connected = False def on_online(): self.__is_connected = True self.__my_iot_mqtt_client.onOffline = on_offline self.__my_iot_mqtt_client.onOnline = on_online # 接続開始 self.__my_iot_mqtt_client.connect() def publish(self, IOT_TOPIC, unpacked_data): if not self.__is_connected: self.__my_iot_mqtt_client.connect() self.__my_iot_mqtt_client.publishAsync(IOT_TOPIC, str(unpacked_data), 1, ackCallback=None) def main(): iot_mqtt_client = IotMqttClient() count = 1 while True: print(count) count += 1 time.sleep(1) send_data = {'key':count} json_data = json.dumps(send_data) iot_mqtt_client.publish('test_topic', json_data) if __name__ == '__main__': main()
よくサンプルで出てくるポリシー
{ "Version": "2012-10-17", "Statement": [ { "Effect": "Allow", "Action": [ "iot:Publish", "iot:Subscribe", "iot:Connect", "iot:Receive" ], "Resource": "*" } ] }
改善したい点
- 機能別に許可するモノを分けたい
- 今回は
testThing
のPublishのみを許可したい
ポリシー例
開発者ガイド>パブリッシュ/サブスクライブポリシーの例参考に作成してみました
{ "Version": "2012-10-17", "Statement": [ { "Effect": "Allow", "Action": [ "iot:Connect" ], "Resource": [ "arn:aws:iot:ap-northeast-1:123456789012:client/testThing" ] }, { "Effect": "Allow", "Action": [ "iot:Publish" ], "Resource": [ "arn:aws:iot:ap-northeast-1:123456789012:topic/testThing/*" ] } ] }
動かしてみた
$ ./shadow.py Connect timed out Traceback (most recent call last): File "./shadow.py", line 74, in <module> main() File "./shadow.py", line 57, in main iot_mqtt_client = IotMqttClient() File "./shadow.py", line 46, in __init__ self.__my_iot_mqtt_client.connect() File "/usr/local/lib/python3.7/site-packages/AWSIoTPythonSDK/MQTTLib.py", line 513, in connect return self._mqtt_core.connect(keepAliveIntervalSecond) File "/usr/local/lib/python3.7/site-packages/AWSIoTPythonSDK/core/protocol/mqtt_core.py", line 199, in connect raise connectTimeoutException() AWSIoTPythonSDK.exception.AWSIoTExceptions.connectTimeoutException
接続できないので確認してみた
- SDK
MQTT Modules
clientID - String that denotes the client identifier used to connect to AWS IoT. If empty string were provided, client id for this connection will be randomly generated n server side.
クライアントIDはAWS IoTへ接続するためのの文字列なのでIOT_CLIENT_ID = 'test_client'
としているとtestThing
を許可しているので接続できませんので修正しましょう。
IOT_CLIENT_ID = 'testThing'
再度動かしてみた
1 2 3 4 5 6 Connect timed out Traceback (most recent call last): File "./shadow.py", line 74, in <module> main() File "./shadow.py", line 67, in main iot_mqtt_client.publish('test_topic', json_data) File "./shadow.py", line 50, in publish self.__my_iot_mqtt_client.connect() File "/usr/local/lib/python3.7/site-packages/AWSIoTPythonSDK/MQTTLib.py", line 513, in connect return self._mqtt_core.connect(keepAliveIntervalSecond) File "/usr/local/lib/python3.7/site-packages/AWSIoTPythonSDK/core/protocol/mqtt_core.py", line 199, in connect raise connectTimeoutException() AWSIoTPythonSDK.exception.AWSIoTExceptions.connectTimeoutException
少し動いたように見えてタイムアウトエラーします。実際AWSマネジメントコンソールからsubscribeしてもデータは取得できませんでした。
確認してみた
- 一旦
pubulish
側の"Resouce"
をワイルドカードにしてみたところpublishできるようになった - と言うことは
pubulish
側の"Resouce"
に問題がある - プログラムの
topic
の書式に間違いがある? - 以下の変更を加えた
iot_mqtt_client.publish('testThing/test_topic', json_data)
- 無事publish成功
AWSマネジメントコンソールからsubscribeしてもデータは取得できることも確認できました。
参考サイト
https://docs.aws.amazon.com/ja_jp/iot/latest/developerguide/pub-sub-policy.html
最後に
ついついサンプルのままポリシーを使っているので、痛い目に合いそうなので修正したところ見事はハマってしまった内容でした。細かい記載ミスでしたので原因を見つけるのに時間がかかりましたが、同じような問題に対して参考になれば幸いです。